/*
 * simple_itc.c
 *
 *  Created on: Apr 13, 2012
 *      Author: drew
 */

#include "simple_itc.h"
#include "simple_linked_list/simple_linked_list.h"
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>

#define MAXNANOSECONDTIME 1000000000

SimItc_QueueHandle_t SimItc_CreateQueue( int length, int size )
{
  SimItc_QueueHandle_t queueHandle;

  /* Initialize Memory for Memory for Message Structure */
  queueHandle = (SimItc_QueueHandle_t) malloc( sizeof(SimItc_ConcreteMsg_t) );
  queueHandle->ConditionLock = malloc( sizeof(pthread_mutex_t) );

  /* Initialize Linked List for Queue */
  queueHandle->LinkedList = xpSimLL_CreateList( size, length );

  /* Initialize Memory for Message Condition */
  queueHandle->Condition = malloc( sizeof(pthread_cond_t) );

  /* Initialize Peripherals */
  pthread_mutex_init( queueHandle->ConditionLock, NULL );
  pthread_cond_init( queueHandle->Condition, NULL );

  return queueHandle;
}

void SimItc_DestroyQueue( SimItc_QueueHandle_t queueHandle )
{

  vSimLL_DestroyList( queueHandle->LinkedList );

  pthread_mutex_destroy( queueHandle->ConditionLock );
  pthread_cond_destroy( queueHandle->Condition );

  free( queueHandle->ConditionLock );
  free( queueHandle->Condition );

  free( queueHandle );
}

int SimItc_SendQueue( SimItc_QueueHandle_t queueHandle,
    const void * pvItemToQueue )
{
  int iQueueFailure = 0, iReturnValue = 0;

  /* Add an Item to the Queue */
  if( (iQueueFailure = iSimLL_AddNodeToList( queueHandle->LinkedList, (void*) pvItemToQueue )) )
  {
    /* TODO: Report Error Here */
    printf( "There was a problem here\n" );
    iReturnValue = 1;
  }
  else
  {
    /* Send Condition Here */
    pthread_cond_signal( queueHandle->Condition );
  }

  return iReturnValue;
}

int SimItc_ReceiveQueue( SimItc_QueueHandle_t queueHandle, void * pvBuffer,
    int iMaxWaitMs )
{
  struct timespec xTimeSpec;
  struct timeval xTimeVal;
  int iReturnValue = 0, my_error;

  if( iSimLL_GetListLength( queueHandle->LinkedList ) )
  {
    /* Get Next Queued Message */
    iSimLL_GetAndRemoveFirstNode( queueHandle->LinkedList, pvBuffer );
  }
  else
  {
    gettimeofday( &xTimeVal, NULL );

    xTimeSpec.tv_sec = xTimeVal.tv_sec + (iMaxWaitMs / 1000);
    xTimeSpec.tv_nsec = ( xTimeVal.tv_usec + ((iMaxWaitMs % 1000) * 1000) ) * 1000;


    if( xTimeSpec.tv_nsec >= MAXNANOSECONDTIME )
    {
      xTimeSpec.tv_nsec %= MAXNANOSECONDTIME;
      xTimeSpec.tv_sec  += 1;
    }

    /* Wait on Timeout or Message Condition */
    if( (my_error = pthread_cond_timedwait( queueHandle->Condition, queueHandle->ConditionLock, &xTimeSpec ) ) )
    {
      if( my_error != ETIMEDOUT )
      {
        printf( "Error: pthread_cond_timedwait: %d\n", my_error );
      }
      else
      {
        iReturnValue = 1;
      }
    }
    else
    {
      iSimLL_GetAndRemoveFirstNode( queueHandle->LinkedList, pvBuffer );
    }
  }

  return iReturnValue;
}

